#ifndef MOONLIGHT_OHOS_GAMESTREAMMANAGER_H
#define MOONLIGHT_OHOS_GAMESTREAMMANAGER_H

#include "core/utils/NapiUtils.h"
#include "XComponentBackend.h"
#include <Limelight.h>
#include <napi/native_api.h>
#include <native_window/external_window.h>
#include <string>
#include <memory>
#include <thread>


class GameStreamManager {

public:
    static napi_status exportNapi(napi_env env, napi_value exports);
    static void cleanup();
private:
    static napi_value on(napi_env env, napi_callback_info info);
    static napi_value startConnection(napi_env env, napi_callback_info info);
    static napi_value stopConnection(napi_env env, napi_callback_info info);

    static napi_value setTouchHandler(napi_env env, napi_callback_info info);
    static napi_value sendKeyEvent(napi_env env, napi_callback_info info);
    static napi_value sendControllerArrivalEvent(napi_env env, napi_callback_info info);
    static napi_value sendMultiControllerEvent(napi_env env, napi_callback_info info);

    static napi_value preDestroy(napi_env env, napi_callback_info info);

public:
    static void emitEvent(const std::string &event, std::initializer_list<NapiUtils::NapiValueType> args);

public:
    static inline SERVER_INFORMATION serverInfo;
    static inline STREAM_CONFIGURATION streamConfig;
    static inline std::string xcomponentId;
    static inline OHNativeWindow *nativeWindow = nullptr;
    static inline std::unique_ptr<XComponentBackend> xcomponentBackend = nullptr;

    static class VideoStats final {
    public:
        VideoStats();
        void clear();
        void setStreamGeometry(int32_t width, int32_t height);
        void setDecoder(const std::string &decoder);
        struct FrameInfo {
            int64_t decodeUnitSize = -1;
            int64_t hostProcessingLatencyTenthMs = -1;
            int64_t requestedAtMs = -1;
            int64_t enqueuedAtMs = -1;
            int64_t receivedAtms = -1;
            int64_t submittedDecodeAtMs = -1;
            int64_t decodedAtMs = -1;
        };
        void reportRequested(uint64_t id);
        void reportSubmitted(
            uint64_t id,
            int64_t belongToFrame,
            int64_t decodeUnitSize,
            int64_t hostProcessingLatencyTenthMs,
            int64_t enqueuedAtMs,
            int64_t receivedAtMs
        );
        void reportDecoded(uint64_t id);
        napi_value toNapiValue(napi_env env) const;

        class Metrics;
    private:
        std::unique_ptr<Metrics> m;
    } videoStats;

private:
    friend XComponentBackend;

    static inline std::mutex callbackMapMtx;
    static inline std::unordered_map<std::string, std::unique_ptr<NapiUtils::ThreadSafeFunction>> callbackMap;

    static inline bool ENABLE_LIMELOG = false;
    static void limeLogCb(const char *fmg, ...);

    static inline std::thread updateVideoStatsThread;
    static void updateVideoStatsHandler();
    static inline std::atomic<bool> stopFlag = false;
    static inline std::condition_variable stopCond;

};


#define ENSURE_GSMGR_OR_ELSE(otherwise) \
    if (!GameStreamManager::xcomponentBackend) { \
        OH_LOG_FATAL(LOG_APP, "GameStreamManager is not functional at the time of this %{public}s invocation", __PRETTY_FUNCTION__); \
        otherwise; \
    }

#endif //MOONLIGHT_OHOS_GAMESTREAMMANAGER_H
